package com.smart.community.work.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.result.Result;
import com.smart.community.commons.utils.DateUtils;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.work.entity.Schedule;
import com.smart.community.work.service.ScheduleService;
import com.smart.community.work.vo.ScheduleVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;

/**
 * 排班管理控制器
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 * @version 1.0.0
 */
@Slf4j
@RestController
@RequestMapping("/work/schedule")
@RequiredArgsConstructor
@Validated
@Tag(name = "排班管理", description = "排班管理相关接口")
public class ScheduleController {

    private final ScheduleService scheduleService;

    @GetMapping("/page")
    @Operation(summary = "分页查询排班计划", description = "分页查询排班计划列表")
    public Result<IPage<ScheduleVO>> selectSchedulePage(
            @Parameter(description = "分页参数") Page<ScheduleVO> page, 
            @Parameter(description = "查询参数") @RequestParam Map<String, Object> params) throws Exception {
        try {
            log.info("开始分页查询排班计划，当前页：{}，每页大小：{}", page.getCurrent(), page.getSize());
            
            IPage<ScheduleVO> result = scheduleService.selectSchedulePage(page, params);
            log.info("分页查询排班计划成功，返回记录数：{}", result.getRecords().size());
            return Result.success("查询成功", result);
        } catch (BusinessException e) {
            log.warn("分页查询排班计划业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("分页查询排班计划系统异常，错误信息：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    @GetMapping("/user/{userId}")
    @Operation(summary = "根据用户ID查询排班计划", description = "根据用户ID查询排班计划")
    public Result<List<ScheduleVO>> selectByUserId(
            @Parameter(description = "用户ID", required = true) @PathVariable @NotNull Long userId,
            @Parameter(description = "开始日期") @RequestParam(required = false) String startDate,
            @Parameter(description = "结束日期") @RequestParam(required = false) String endDate) throws Exception {
        try {
            log.info("开始根据用户ID查询排班计划，用户ID：{}，开始日期：{}，结束日期：{}", userId, startDate, endDate);
            
            // 参数校验
            if (userId == null || userId <= 0) {
                return Result.fail("用户ID必须大于0");
            }
            
            // 日期参数解析
            LocalDate startDateParsed = null;
            if (startDate != null && !startDate.trim().isEmpty()) {
                try {
                    startDateParsed = DateUtils.parseDate(startDate);
                    if (startDateParsed == null) {
                        return Result.fail("开始日期格式不正确，请使用 yyyy-MM-dd 格式");
                    }
                } catch (Exception e) {
                    log.error("解析开始日期失败: {}", startDate, e);
                    return Result.fail("开始日期格式不正确，请使用 yyyy-MM-dd 格式");
                }
            }
            
            LocalDate endDateParsed = null;
            if (endDate != null && !endDate.trim().isEmpty()) {
                try {
                    endDateParsed = DateUtils.parseDate(endDate);
                    if (endDateParsed == null) {
                        return Result.fail("结束日期格式不正确，请使用 yyyy-MM-dd 格式");
                    }
                } catch (Exception e) {
                    log.error("解析结束日期失败: {}", endDate, e);
                    return Result.fail("结束日期格式不正确，请使用 yyyy-MM-dd 格式");
                }
            }
            
            // 日期范围验证
            if (startDateParsed != null && endDateParsed != null && startDateParsed.isAfter(endDateParsed)) {
                return Result.fail("开始日期不能晚于结束日期");
            }
            
            List<ScheduleVO> result = scheduleService.selectByUserId(userId, startDateParsed, endDateParsed);
            log.info("根据用户ID查询排班计划成功，返回记录数：{}", result.size());
            return Result.success("查询成功", result);
        } catch (BusinessException e) {
            log.warn("根据用户ID查询排班计划业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("根据用户ID查询排班计划系统异常，用户ID：{}，错误信息：{}", userId, e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    @GetMapping("/date/{scheduleDate}")
    @Operation(summary = "根据排班日期查询排班计划", description = "根据排班日期查询排班计划")
    public Result<List<ScheduleVO>> selectByScheduleDate(
            @Parameter(description = "排班日期", required = true) @PathVariable @NotNull LocalDate scheduleDate, 
            @Parameter(description = "物业公司ID", required = true) @RequestParam @NotNull Long propertyCompanyId) throws Exception {
        try {
            log.info("开始根据排班日期查询排班计划，排班日期：{}，物业公司ID：{}", scheduleDate, propertyCompanyId);
            
            // 参数校验
            if (scheduleDate == null) {
                return Result.fail("排班日期不能为空");
            }
            if (propertyCompanyId == null || propertyCompanyId <= 0) {
                return Result.fail("物业公司ID必须大于0");
            }
            
            List<ScheduleVO> result = scheduleService.selectByScheduleDate(scheduleDate, propertyCompanyId);
            log.info("根据排班日期查询排班计划成功，返回记录数：{}", result.size());
            return Result.success("查询成功", result);
        } catch (BusinessException e) {
            log.warn("根据排班日期查询排班计划业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("根据排班日期查询排班计划系统异常，排班日期：{}，错误信息：{}", scheduleDate, e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    @PostMapping
    @Operation(summary = "创建排班计划", description = "创建排班计划")
    public Result<Boolean> createSchedule(@Parameter(description = "排班计划信息", required = true) @Valid @RequestBody Schedule schedule) throws Exception {
        try {
            log.info("开始创建排班计划，用户ID：{}，排班日期：{}", schedule.getUserId(), schedule.getScheduleDate());
            
            // 参数校验
            if (schedule.getUserId() == null || schedule.getUserId() <= 0) {
                return Result.fail("用户ID不能为空且必须大于0");
            }
            if (schedule.getScheduleDate() == null) {
                return Result.fail("排班日期不能为空");
            }
            if (schedule.getShiftType() == null || schedule.getShiftType().trim().isEmpty()) {
                return Result.fail("班次类型不能为空");
            }
            
            Boolean result = scheduleService.createSchedule(schedule);
            log.info("创建排班计划成功，用户ID：{}，结果：{}", schedule.getUserId(), result);
            return Result.success("创建成功", result);
        } catch (BusinessException e) {
            log.warn("创建排班计划业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("创建排班计划系统异常，错误信息：{}", e.getMessage(), e);
            return Result.fail("创建失败：" + e.getMessage());
        }
    }

    @PostMapping("/batch")
    @Operation(summary = "批量创建排班计划", description = "批量创建排班计划")
    public Result<Boolean> batchCreateSchedule(@Parameter(description = "排班计划列表", required = true) @Valid @RequestBody @NotEmpty List<Schedule> schedules) throws Exception {
        try {
            log.info("开始批量创建排班计划，数量：{}", schedules.size());
            
            // 参数校验
            if (schedules == null || schedules.isEmpty()) {
                return Result.fail("排班计划列表不能为空");
            }
            
            // 验证每个排班计划的基本信息
            for (Schedule schedule : schedules) {
                if (schedule.getUserId() == null || schedule.getUserId() <= 0) {
                    return Result.fail("用户ID不能为空且必须大于0");
                }
                if (schedule.getScheduleDate() == null) {
                    return Result.fail("排班日期不能为空");
                }
                if (schedule.getShiftType() == null || schedule.getShiftType().trim().isEmpty()) {
                    return Result.fail("班次类型不能为空");
                }
            }
            
            Boolean result = scheduleService.batchCreateSchedule(schedules);
            log.info("批量创建排班计划成功，数量：{}，结果：{}", schedules.size(), result);
            return Result.success("批量创建成功", result);
        } catch (BusinessException e) {
            log.warn("批量创建排班计划业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("批量创建排班计划系统异常，错误信息：{}", e.getMessage(), e);
            return Result.fail("批量创建失败：" + e.getMessage());
        }
    }

    @PutMapping
    @Operation(summary = "更新排班计划", description = "更新排班计划")
    public Result<Boolean> updateSchedule(@Parameter(description = "排班计划信息", required = true) @Valid @RequestBody Schedule schedule) throws Exception {
        try {
            log.info("开始更新排班计划，ID：{}", schedule.getId());
            
            // 参数校验
            if (schedule.getId() == null || schedule.getId() <= 0) {
                return Result.fail("排班计划ID必须大于0");
            }
            if (schedule.getUserId() == null || schedule.getUserId() <= 0) {
                return Result.fail("用户ID不能为空且必须大于0");
            }
            if (schedule.getScheduleDate() == null) {
                return Result.fail("排班日期不能为空");
            }
            if (schedule.getShiftType() == null || schedule.getShiftType().trim().isEmpty()) {
                return Result.fail("班次类型不能为空");
            }
            
            Boolean result = scheduleService.updateSchedule(schedule);
            log.info("更新排班计划成功，ID：{}，结果：{}", schedule.getId(), result);
            return Result.success("更新成功", result);
        } catch (BusinessException e) {
            log.warn("更新排班计划业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("更新排班计划系统异常，错误信息：{}", e.getMessage(), e);
            return Result.fail("更新失败：" + e.getMessage());
        }
    }

    @PostMapping("/change")
    @Operation(summary = "调班申请", description = "调班申请")
    public Result<Boolean> applyScheduleChange(
            @Parameter(description = "原排班ID", required = true) @RequestParam @NotNull Long originalScheduleId,
            @Parameter(description = "目标排班ID", required = true) @RequestParam @NotNull Long targetScheduleId,
            @Parameter(description = "申请人ID", required = true) @RequestParam @NotNull Long applicantId,
            @Parameter(description = "调班原因", required = true) @RequestParam @NotNull String changeReason) throws Exception {
        try {
            log.info("开始调班申请，原排班ID：{}，目标排班ID：{}，申请人ID：{}", originalScheduleId, targetScheduleId, applicantId);
            
            // 参数校验
            if (originalScheduleId == null || originalScheduleId <= 0) {
                return Result.fail("原排班ID必须大于0");
            }
            if (targetScheduleId == null || targetScheduleId <= 0) {
                return Result.fail("目标排班ID必须大于0");
            }
            if (applicantId == null || applicantId <= 0) {
                return Result.fail("申请人ID必须大于0");
            }
            if (changeReason == null || changeReason.trim().isEmpty()) {
                return Result.fail("调班原因不能为空");
            }
            
            Boolean result = scheduleService.applyScheduleChange(originalScheduleId, targetScheduleId, applicantId, changeReason);
            log.info("调班申请成功，原排班ID：{}，结果：{}", originalScheduleId, result);
            return Result.success("申请成功", result);
        } catch (BusinessException e) {
            log.warn("调班申请业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("调班申请系统异常，错误信息：{}", e.getMessage(), e);
            return Result.fail("申请失败：" + e.getMessage());
        }
    }

    @PostMapping("/change/approve/{changeId}")
    @Operation(summary = "审批调班申请", description = "审批调班申请")
    public Result<Boolean> approveScheduleChange(
            @Parameter(description = "调班申请ID", required = true) @PathVariable @NotNull Long changeId,
            @Parameter(description = "审批状态", required = true) @RequestParam @NotNull Integer status,
            @Parameter(description = "审批人ID", required = true) @RequestParam @NotNull Long approverId,
            @Parameter(description = "审批备注") @RequestParam(required = false) String approveRemark) throws Exception {
        try {
            log.info("开始审批调班申请，调班申请ID：{}，状态：{}，审批人ID：{}", changeId, status, approverId);
            
            // 参数校验
            if (changeId == null || changeId <= 0) {
                return Result.fail("调班申请ID必须大于0");
            }
            if (status == null) {
                return Result.fail("审批状态不能为空");
            }
            if (approverId == null || approverId <= 0) {
                return Result.fail("审批人ID必须大于0");
            }
            
            Boolean result = scheduleService.approveScheduleChange(changeId, status, approverId, approveRemark);
            log.info("审批调班申请成功，调班申请ID：{}，结果：{}", changeId, result);
            return Result.success("审批成功", result);
        } catch (BusinessException e) {
            log.warn("审批调班申请业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("审批调班申请系统异常，调班申请ID：{}，错误信息：{}", changeId, e.getMessage(), e);
            return Result.fail("审批失败：" + e.getMessage());
        }
    }

    @GetMapping("/statistics")
    @Operation(summary = "统计排班数据", description = "统计排班数据")
    public Result<Map<String, Object>> getScheduleStatistics(
            @Parameter(description = "物业公司ID", required = true) @RequestParam @NotNull Long propertyCompanyId,
            @Parameter(description = "开始日期", required = true) @RequestParam @NotNull LocalDate startDate,
            @Parameter(description = "结束日期", required = true) @RequestParam @NotNull LocalDate endDate) throws Exception {
        try {
            log.info("开始统计排班数据，物业公司ID：{}，开始日期：{}，结束日期：{}", propertyCompanyId, startDate, endDate);
            
            // 参数校验
            if (propertyCompanyId == null || propertyCompanyId <= 0) {
                return Result.fail("物业公司ID必须大于0");
            }
            if (startDate == null || endDate == null) {
                return Result.fail("开始日期和结束日期不能为空");
            }
            if (startDate.isAfter(endDate)) {
                return Result.fail("开始日期不能晚于结束日期");
            }
            
            Map<String, Object> result = scheduleService.getScheduleStatistics(propertyCompanyId, startDate, endDate);
            log.info("统计排班数据成功，物业公司ID：{}", propertyCompanyId);
            return Result.success("统计成功", result);
        } catch (BusinessException e) {
            log.warn("统计排班数据业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("统计排班数据系统异常，错误信息：{}", e.getMessage(), e);
            return Result.fail("统计失败：" + e.getMessage());
        }
    }

    @GetMapping("/conflict")
    @Operation(summary = "检查排班冲突", description = "检查排班冲突")
    public Result<Boolean> checkScheduleConflict(
            @Parameter(description = "用户ID", required = true) @RequestParam @NotNull Long userId,
            @Parameter(description = "排班日期", required = true) @RequestParam @NotNull LocalDate scheduleDate,
            @Parameter(description = "班次类型", required = true) @RequestParam @NotNull String shiftType,
            @Parameter(description = "排除的排班ID") @RequestParam(required = false) Long excludeId) throws Exception {
        try {
            log.info("开始检查排班冲突，用户ID：{}，排班日期：{}，班次类型：{}", userId, scheduleDate, shiftType);
            
            // 参数校验
            if (userId == null || userId <= 0) {
                return Result.fail("用户ID必须大于0");
            }
            if (scheduleDate == null) {
                return Result.fail("排班日期不能为空");
            }
            if (shiftType == null || shiftType.trim().isEmpty()) {
                return Result.fail("班次类型不能为空");
            }
            
            Boolean result = scheduleService.checkScheduleConflict(userId, scheduleDate, shiftType, excludeId);
            log.info("检查排班冲突成功，用户ID：{}，结果：{}", userId, result);
            return Result.success("检查成功", result);
        } catch (BusinessException e) {
            log.warn("检查排班冲突业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("检查排班冲突系统异常，错误信息：{}", e.getMessage(), e);
            return Result.fail("检查失败：" + e.getMessage());
        }
    }

    @PutMapping("/{id}/status")
    @Operation(summary = "更新排班状态", description = "更新排班状态")
    public Result<Boolean> updateStatus(
            @Parameter(description = "排班计划ID", required = true) @PathVariable @NotNull Long id, 
            @Parameter(description = "状态", required = true) @RequestParam @NotNull Integer status) throws Exception {
        try {
            log.info("开始更新排班状态，ID：{}，状态：{}", id, status);
            
            // 参数校验
            if (id == null || id <= 0) {
                return Result.fail("排班计划ID必须大于0");
            }
            if (status == null) {
                return Result.fail("状态不能为空");
            }
            
            Boolean result = scheduleService.updateStatus(id, status, SecurityUtils.getCurrentUserId());
            log.info("更新排班状态成功，ID：{}，结果：{}", id, result);
            return Result.success("更新成功", result);
        } catch (BusinessException e) {
            log.warn("更新排班状态业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("更新排班状态系统异常，ID：{}，错误信息：{}", id, e.getMessage(), e);
            return Result.fail("更新失败：" + e.getMessage());
        }
    }

    @DeleteMapping("/{id}")
    @Operation(summary = "删除排班计划", description = "删除排班计划")
    public Result<Boolean> deleteById(@Parameter(description = "排班计划ID", required = true) @PathVariable @NotNull Long id) throws Exception {
        try {
            log.info("开始删除排班计划，ID：{}", id);
            
            // 参数校验
            if (id == null || id <= 0) {
                return Result.fail("排班计划ID必须大于0");
            }
            
            Boolean result = scheduleService.deleteById(id, SecurityUtils.getCurrentUserId());
            log.info("删除排班计划成功，ID：{}，结果：{}", id, result);
            return Result.success("删除成功", result);
        } catch (BusinessException e) {
            log.warn("删除排班计划业务异常：{}", e.getMessage());
            return Result.fail(e.getMessage());
        } catch (Exception e) {
            log.error("删除排班计划系统异常，ID：{}，错误信息：{}", id, e.getMessage(), e);
            return Result.fail("删除失败：" + e.getMessage());
        }
    }
}
